package com.gitee.wsl.ext.coroutines

import kotlinx.atomicfu.AtomicBoolean
import kotlinx.atomicfu.AtomicInt
import kotlinx.atomicfu.AtomicLong
import kotlinx.atomicfu.AtomicRef
import kotlinx.atomicfu.atomic
import kotlinx.atomicfu.update

fun <V> AtomicRef<V>.get() = value

fun <V> AtomicRef<V>.set(value:V) = update{ _ -> value }


/**
 * Infinite loop that reads this atomic variable and performs the specified [action] on its value.
 */
 //inline fun <V> AtomicRef<V>.loop(action: (V) -> Unit): Nothing { while(true) { action(value) } }

 inline fun <V> AtomicRef<V>.tryUpdate(function: (V) -> V): Boolean = tryUpdate(function) { _, _ -> }

 //inline fun <V> AtomicRef<V>.update(function: (V) -> V): Unit = update(function) { _, _ -> }


fun te(){
    val a = atomic(10)

}


/**
 * Updates variable atomically using the specified [function] of its value and returns its old value.
 */
 //inline fun <V> AtomicRef<V>.getAndUpdate(function: (V) -> V): V = update(function) { old, _ -> old }

/**
 * Updates variable atomically using the specified [function] of its value and returns its new value.
 */
//inline fun <V> AtomicRef<V>.updateAndGet(function: (V) -> V): V = update(function) { _, new -> new }

@PublishedApi
internal inline fun <V, U: V, R> AtomicRef<V>.update(function: (V) -> U, transform: (old: V, new: U) -> R): R {
    while (true) {
        tryUpdate(function) { old, new -> return transform(old, new) }
    }
}

@PublishedApi
internal inline fun <V, U: V> AtomicRef<V>.tryUpdate(function: (V) -> U, onUpdated: (old: V, new: U) -> Unit): Boolean {
    val cur = value
    val upd = function(cur)
    return compareAndSet(cur, upd).also { if (it) onUpdated(cur, upd) }
}


/**
 * Infinite loop that reads this atomic variable and performs the specified [action] on its value.
 */
 //inline fun AtomicBoolean.loop(action: (Boolean) -> Unit): Nothing { while(true) { action(value) } }

 inline fun AtomicBoolean.tryUpdate(function: (Boolean) -> Boolean): Boolean = tryUpdate(function) { _, _ -> }

 //inline fun AtomicBoolean.update(function: (Boolean) -> Boolean): Unit = update(function) { _, _ -> }

/**
 * Updates variable atomically using the specified [function] of its value and returns its old value.
 */
//inline fun AtomicBoolean.getAndUpdate(function: (Boolean) -> Boolean): Boolean = update(function) { old, _ -> old }

/**
 * Updates variable atomically using the specified [function] of its value and returns its new value.
 */
//inline fun AtomicBoolean.updateAndGet(function: (Boolean) -> Boolean): Boolean = update(function) { _, new -> new }

@PublishedApi
internal inline fun <R> AtomicBoolean.update(function: (Boolean) -> Boolean, transform: (old: Boolean, new: Boolean) -> R): R {
    while (true) {
        tryUpdate(function) { old, new -> return transform(old, new) }
    }
}

@PublishedApi
internal inline fun AtomicBoolean.tryUpdate(function: (Boolean) -> Boolean, onUpdated: (old: Boolean, new: Boolean) -> Unit): Boolean {
    val cur = value
    val upd = function(cur)
    return compareAndSet(cur, upd).also { if (it) onUpdated(cur, upd) }
}

/**
 * Infinite loop that reads this atomic variable and performs the specified [action] on its value.
 */
 //inline fun AtomicInt.loop(action: (Int) -> Unit): Nothing { while(true) { action(value) } }

 inline fun AtomicInt.tryUpdate(function: (Int) -> Int): Boolean = tryUpdate(function) { _, _ -> }

 //inline fun AtomicInt.update(function: (Int) -> Int) : Unit = update(function) { _, _ -> }

/**
 * Updates variable atomically using the specified [function] of its value and returns its old value.
 */
// inline fun AtomicInt.getAndUpdate(function: (Int) -> Int): Int = update(function) { old, _ -> old }

/**
 * Updates variable atomically using the specified [function] of its value and returns its new value.
 */
//inline fun AtomicInt.updateAndGet(function: (Int) -> Int): Int = update(function) { _, new -> new }

@PublishedApi
internal inline fun <R> AtomicInt.update(function: (Int) -> Int, transform: (old: Int, new: Int) -> R): R {
    while (true) {
        tryUpdate(function) { old, new -> return transform(old, new) }
    }
}

@PublishedApi
internal inline fun AtomicInt.tryUpdate(function: (Int) -> Int, onUpdated: (old: Int, new: Int) -> Unit): Boolean {
    val cur = value
    val upd = function(cur)
    return compareAndSet(cur, upd).also { if (it) onUpdated(cur, upd) }
}


/**
 * Infinite loop that reads this atomic variable and performs the specified [action] on its value.
 */
 //inline fun AtomicLong.loop(action: (Long) -> Unit): Nothing { while(true) { action(value) } }

 inline fun AtomicLong.tryUpdate(function: (Long) -> Long): Boolean = tryUpdate(function) { _, _ -> }

 //inline fun AtomicLong.update(function: (Long) -> Long): Unit = update(function) { _, _ -> }

/**
 * Updates variable atomically using the specified [function] of its value and returns its old value.
 */
 //inline fun AtomicLong.getAndUpdate(function: (Long) -> Long): Long = update(function) { old, _ -> old }

/**
 * Updates variable atomically using the specified [function] of its value and returns its new value.
 */
//inline fun AtomicLong.updateAndGet(function: (Long) -> Long): Long = update(function) { _, new -> new }

@PublishedApi
internal inline fun <R> AtomicLong.update(function: (Long) -> Long, transform: (old: Long, new: Long) -> R): R {
    while (true) {
        tryUpdate(function) { old, new -> return transform(old, new) }
    }
}

@PublishedApi
internal inline fun AtomicLong.tryUpdate(function: (Long) -> Long, onUpdated: (old: Long, new: Long) -> Unit): Boolean {
    val cur = value
    val upd = function(cur)
    return compareAndSet(cur, upd).also { if (it) onUpdated(cur, upd) }
}

/**
 *  Increases an AtomicInteger safely.
 */
fun AtomicInt.getAndIncrementNoOverflow() {
    var prev: Int
    var next: Int
    do {
        prev = this.value
        next = if (prev == Int.MAX_VALUE) prev else prev + 1
    } while (!this.compareAndSet(prev, next))
}